/**
 * Copyright (c) 2011-2014, hubin (jobob@qq.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.kingtop.mybatis.plugin;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.RowBounds;
import org.kingtop.mybatis.plugin.dialect.DB2Dialect;
import org.kingtop.mybatis.plugin.dialect.H2Dialect;
import org.kingtop.mybatis.plugin.dialect.HSQLDialect;
import org.kingtop.mybatis.plugin.dialect.IDialect;
import org.kingtop.mybatis.plugin.dialect.MySqlDialect;
import org.kingtop.mybatis.plugin.dialect.OracleDialect;
import org.kingtop.mybatis.plugin.dialect.PostgreDialect;
import org.kingtop.mybatis.plugin.dialect.SQLServer2005Dialect;
import org.kingtop.mybatis.plugin.dialect.SQLServerDialect;
import org.kingtop.mybatis.plugin.dialect.SQLiteDialect;
import org.kingtop.mybatis.util.JdbcConstants;

/**
 * <p>
 * 分页方言工厂类
 * </p>
 *
 * @author hubin,陈金波 修改
 * @Date 2016-01-23
 */
public class DialectFactory {

	/**
	 * Physical Pagination Interceptor for all the queries with parameter
	 * {@link org.apache.ibatis.session.RowBounds}
	 *
	 * @param rowBounds
	 * @param buildSql
	 * @param dbType
	 * @param dialectClazz
	 * @return
	 * @throws Exception
	 */
	public static String buildPageSql(RowBounds rowBounds, String buildSql, String dbType, String dialectClazz)
			throws Exception {
		// fix #196
		return getDialect(dbType, dialectClazz).buildPaginationSql(buildSql, rowBounds.getOffset(),
				rowBounds.getLimit());
	}

	public static String buildPageSqlWithPage(int pageIndex, int pageSize, String buildSql, String dbType,
			String dialectClazz) throws Exception {
		int offset = (pageIndex - 1) * pageSize;
		return buildPageSql(offset, pageSize, buildSql, dbType, dialectClazz);
	}

	public static String buildPageSql(int offset, int limit, String buildSql, String dbType, String dialectClazz)
			throws Exception {
		return getDialect(dbType, dialectClazz).buildPaginationSql(buildSql, offset, limit);
	}

	/**
	 * <p>
	 * 获取数据库方言
	 * </p>
	 *
	 * @param dbType
	 *            数据库类型
	 * @param dialectClazz
	 *            自定义方言实现类
	 * @return
	 * @throws Exception
	 */
	private static IDialect getDialect(String dbType, String dialectClazz) throws Exception {
		IDialect dialect = null;
		if (StringUtils.isNotBlank(dialectClazz)) {
			try {
				Class<?> clazz = Class.forName(dialectClazz);
				if (IDialect.class.isAssignableFrom(clazz)) {
					dialect = (IDialect) clazz.newInstance();
				}
			} catch (ClassNotFoundException e) {
				throw new IllegalArgumentException("Class :" + dialectClazz + " is not found");
			}
		} else if (null != dbType) {
			dialect = getDialectByDbtype(dbType);
		}
		/* 未配置方言则抛出异常 */
		if (dialect == null) {
			throw new IllegalArgumentException(
					"The value of the dialect property in mybatis configuration.xml is not defined.");
		}
		return dialect;
	}

	/**
	 * <p>
	 * 根据数据库类型选择不同分页方言
	 * </p>
	 *
	 * @param dbType
	 *            数据库类型
	 * @return
	 * @throws Exception
	 */
	private static IDialect getDialectByDbtype(String dbType) {
		IDialect dialect;
		switch (dbType) {
		case JdbcConstants.MYSQL:
			dialect = MySqlDialect.INSTANCE;
			break;
		case JdbcConstants.ORACLE:
			dialect = OracleDialect.INSTANCE;
			break;
		case JdbcConstants.DB2:
			dialect = DB2Dialect.INSTANCE;
			break;
		case JdbcConstants.H2:
			dialect = H2Dialect.INSTANCE;
			break;
		case JdbcConstants.SQL_SERVER:
			dialect = SQLServerDialect.INSTANCE;
			break;
		case JdbcConstants.SQL_SERVER_2005:
			dialect = SQLServer2005Dialect.INSTANCE;
			break;
		case JdbcConstants.POSTGRESQL:
			dialect = PostgreDialect.INSTANCE;
			break;
		case JdbcConstants.HSQL:
			dialect = HSQLDialect.INSTANCE;
			break;
		case JdbcConstants.SQLITE:
			dialect = SQLiteDialect.INSTANCE;
			break;
		default:
			throw new IllegalArgumentException("The Database's Not Supported! DBType:" + dbType);
		}
		return dialect;
	}

}
